package com.tange.ai.iot.client.gnssa.play

//import com.tange.module.media.play.util.BitmapUtil
import android.Manifest
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.Rect
import android.media.AudioManager
import android.media.MediaScannerConnection
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.net.TrafficStats
import android.net.Uri
import android.net.wifi.WifiConfiguration
import android.net.wifi.WifiManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.Handler
import android.text.TextUtils
import android.util.Log
import android.view.Gravity
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.View
import android.view.ViewTreeObserver
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.util.Consumer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import base.http.rxandroid.CustomDisposableSubscriberNew
import base.utils.LoadMoreAdapter
import base.utils.LogUtil
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.ScreenUtils
import com.blankj.utilcode.util.TimeUtils.millis2String
import com.blankj.utilcode.util.ToastUtils
import com.blankj.utilcode.util.VolumeUtils
import com.bumptech.glide.Glide
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.gyf.immersionbar.BarHide
import com.gyf.immersionbar.ImmersionBar
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.tange.ai.iot.client.gnssa.R
import com.tange.ai.iot.client.gnssa.bean.JpgBeanV2
import com.tange.ai.iot.client.gnssa.bean.NewRecordingData
import com.tange.ai.iot.client.gnssa.bean.RecordingData
import com.tange.ai.iot.client.gnssa.databinding.ActivityDeviceLiveBinding
import com.tange.ai.iot.client.gnssa.httpservice.MainService
import com.tange.ai.iot.client.gnssa.utils.CacheFileManager
import com.tange.ai.iot.client.gnssa.utils.HexConverter
import com.tange.ai.iot.client.gnssa.utils.JsonConverter
import com.tange.ai.iot.client.gnssa.utils.MediaSaver
import com.tange.ai.iot.client.gnssa.utils.ThumbnailResponse.ResponseParser
import com.tange.ai.iot.client.gnssa.utils.Utils
import com.tange.ai.iot.client.gnssa.utils.VrThumbnailParser
import com.tange.ai.iot.client.gnssa.utils.WifiUtils
import com.tange.ai.iot.client.gnssa.view.VerticalSeekBar
import com.tange.ai.iot.client.gnssa.view.popup.DownloadPopup
import com.tange.ai.iot.client.gnssa.view.popup.NormalMsgVPopup
import com.tange.ai.iot.core.media.capture.video.CameraId
import com.tange.ai.iot.core.media.capture.video.CaptureObserver
import com.tange.ai.iot.core.media.capture.video.CodecType
import com.tange.ai.iot.core.media.capture.video.VideoCapture
import com.tange.ai.iot.core.media.capture.video.VideoCaptureConfigure
import com.tange.ai.iot.core.media.capture.video.VideoFrame
import com.tange.ai.iot.core.media.capture.video.processor.RotationProcessor
import com.tange.base.toolkit.DateUtil
import com.tange.base.toolkit.Tips
import com.tange.base.toolkit.gone
import com.tange.base.toolkit.invisible
import com.tange.base.toolkit.isVisible
import com.tange.base.toolkit.onClicked
import com.tange.base.toolkit.ui
import com.tange.base.toolkit.visible
import com.tange.core.device.facade.ConnectStatus
import com.tange.core.device.facade.ConnectionMode
import com.tange.core.device.facade.DeviceFacade
import com.tange.core.device.facade.Status
import com.tange.core.device.manage.DeviceInfoQuery
import com.tange.core.media.captor.MediaCaptor
import com.tange.core.media.render.AudioMode
import com.tange.core.media.render.DeviceMediaRender
import com.tange.core.media.render.DeviceScreenRecord
import com.tange.core.media.source.impl.live.DeviceLiveMediaSource
import com.tange.core.media.source.impl.local.DeviceStorageMediaSource
import com.tange.core.media.source.impl.local.DeviceStoragePlayback
import com.tange.core.trouble.shooting.entry.DebuggingAssistant
import com.tange.core.universal.instructions.BasicInstruction
import com.tange.core.universal.instructions.FeederInstruction
import com.tange.core.universal.instructions.StorageInstruction
import com.tange.module.socket.SocketIoManager
import com.tg.appcommon.android.Packet
import com.tg.appcommon.android.TGLog
import com.tg.data.media.AudioRecorder
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.subscribeBy
import io.reactivex.schedulers.Schedulers
import okhttp3.OkHttpClient
import org.apache.http.conn.ssl.AllowAllHostnameVerifier
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import zlc.season.rxdownload4.download
import zlc.season.rxdownload4.file
import java.io.File
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.TimeZone
import java.util.concurrent.TimeUnit


class DeviceLiveActivity : AppCompatActivity() {

    companion object {
        private const val TAG = "DeviceLiveActivity_"
        private const val PARAM_DEVICE_ID = "PARAM_DEVICE_ID"
        private const val PARAM_VIDEO_COVER = "PARAM_VIDEO_COVER"
        private const val PARAM_LAN_MODE = "PARAM_LAN_MODE"
        private const val INSTRUCTION_DEV_INFO_REQ = 0x0330
        private const val ROTATE_90_ON_CAPTURE = false // 演示视频采集的旋转能力
        private const val TCI_CMD_DEV_REBOOT_REQ = 0x8010 //重启
        private var mMode: ConnectionMode? = null
        private const val TCI_CMD_DEV_DOWNLOAD_REQ = 0x9130 //下载
        private const val TCI_CMD_DEV_JPG_REQ = 0x9136 //下载

        private const val TYPE_DOWNLOAD_VIDEO = "download_video"
        private const val TYPE_DOWNLOAD_JPG = "download_jpg"

        fun launch(context: Context, deviceId: String, videoCoverUrl: String = "") {
            context.startActivity(Intent(context, DeviceLiveActivity::class.java).apply {
                putExtra(PARAM_DEVICE_ID, deviceId)
                putExtra(PARAM_VIDEO_COVER, videoCoverUrl)
            })
        }

        fun launchLanMode(context: Context, deviceId: String) {
            context.startActivity(Intent(context, DeviceLiveActivity::class.java).apply {
                putExtra(PARAM_DEVICE_ID, deviceId)
                putExtra(PARAM_LAN_MODE, true)
            })
        }

        private const val LOCATION_PERMISSION_CODE = 100
        private const val SSID = "GNSSA_1E4EF5"
        private const val PASSWORD = "GNSSAG20"
    }

    fun isConnectedToTargetWifi(context: Context, targetSsid: String): Boolean {
        val wifiManager =
            context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val wifiInfo = wifiManager.connectionInfo

        // 获取当前 SSID (可能为 null 或 "<unknown ssid>")
        val currentSsid = wifiInfo.ssid?.takeIf { it.isNotBlank() }

        return when {
            // 处理未连接 Wi-Fi 的情况
            currentSsid == null -> false
            currentSsid == WifiManager.UNKNOWN_SSID -> false

            // 比较 SSID (需处理引号包裹的情况)
            else -> TextUtils.equals(
                targetSsid.removeSurrounding("\""),
                currentSsid.removeSurrounding("\"")
            )
        }
    }

    private var downLoadPopup: DownloadPopup? = null
    private lateinit var wifiManager: WifiManager

    private var playbackQuery: DeviceStoragePlayback? = null
    private var mTouchOutsideView1: View? = null
    private fun setOnTouchOutsideViewListener1(
        view: View,
        onTouchOutsideViewListener: OnTouchOutsideViewListener1
    ) {
        mTouchOutsideView1 = view
        mOnTouchOutsideViewListener1 = onTouchOutsideViewListener
    }

    private var mOnTouchOutsideViewListener1: OnTouchOutsideViewListener1? = null

    private var storageInstruction: StorageInstruction? = null

    public interface OnTouchOutsideViewListener1 {

        /**
         * Called when a touch event has occurred outside a given view.
         *
         * @param view  The view that has not been touched.
         * @param event The MotionEvent object containing full information about the event.
         */
        public fun onTouchOutside(view: View, event: MotionEvent)
    }

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        if (ev.action == MotionEvent.ACTION_DOWN) {
            // Notify touch outside listener if user tapped outside a given view
            if (mOnTouchOutsideViewListener1 != null && mTouchOutsideView1 != null
                && mTouchOutsideView1!!.visibility == View.VISIBLE
            ) {
                val viewRect1 = Rect()
                mTouchOutsideView1!!.getGlobalVisibleRect(viewRect1)
                if (!viewRect1.contains(ev.rawX.toInt(), ev.rawY.toInt())) {
                    mOnTouchOutsideViewListener1!!.onTouchOutside(mTouchOutsideView1!!, ev)
                }
            }
        }
        return super.dispatchTouchEvent(ev)
    }


    private var albumPath = Environment.getExternalStorageDirectory()
        .toString() + File.separator + Environment.DIRECTORY_DCIM

    private lateinit var deviceId: String

    private lateinit var binding: ActivityDeviceLiveBinding

    private lateinit var deviceFacade: DeviceFacade
    private lateinit var deviceLiveMediaSource: DeviceLiveMediaSource
    private lateinit var deviceMediaRender: DeviceMediaRender
    private lateinit var deviceMediaRenderRecode: DeviceMediaRender

    private var lastDelayUpdate = 0L
    private var isLandscape = false
    private var rendered = false
    private var hasSdCard = false

    /** 本地直连模式 */
    private var lanMode = false

    private var timeZone: TimeZone = TimeZone.getDefault()

    private var mediaCaptor: MediaCaptor? = null

    private var deviceSupportAec = false

    private lateinit var connectStatusObserver: Consumer<ConnectStatus>

    private var videoCaptureConfigure: VideoCaptureConfigure? = null
    private var fileName = ""

    private var width = 0
    private var height = 0
    private var playerHeight = 0
    private var mAdapter: LoadMoreAdapter<NewRecordingData>? = null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ImmersionBar.with(this).statusBarColor(R.color.basic_color_secondary_2)
            .fitsSystemWindows(true).statusBarDarkFont(false, 0.2f)
            .autoStatusBarDarkModeEnable(true, 0.2f).autoDarkModeEnable(true)
            .init();

        Handler().postDelayed(Runnable {
            ImmersionBar.with(this).reset()
            ImmersionBar.with(this).statusBarColor(R.color.basic_color_secondary_2)
                .fitsSystemWindows(true).statusBarDarkFont(false, 0.2f)
                .autoStatusBarDarkModeEnable(true, 0.2f).autoDarkModeEnable(true)
                .init();
        }, 10)


        wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager

        width = ScreenUtils.getAppScreenWidth()
        height = ScreenUtils.getAppScreenHeight()


        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        binding = ActivityDeviceLiveBinding.inflate(layoutInflater).apply {
            setContentView(root)
            supportActionBar?.hide()
            Utils.setDarkStatusBar(this@DeviceLiveActivity, Color.TRANSPARENT)
        }



        deviceId = intent.getStringExtra(PARAM_DEVICE_ID)!!
        lanMode = intent.getBooleanExtra(PARAM_LAN_MODE, false)

        val coverUrl =
            if (intent.hasExtra(PARAM_VIDEO_COVER)) intent.getStringExtra(PARAM_VIDEO_COVER) else ""
        if (!TextUtils.isEmpty(coverUrl)) {
            binding.cover.visible()
            Glide.with(this@DeviceLiveActivity).load(coverUrl).into(binding.cover)
        }

        // 初始化调试助手，设置 顶部的 标题 为触发入口
        DebuggingAssistant.attach(this, binding.tvTitle).apply {
            deviceId = this@DeviceLiveActivity.deviceId
        }

        connectStatusObserver = Consumer<ConnectStatus> {
            LogUtil.e("本地连接:" + GsonUtils.toJson(it))
            TGLog.i(TAG, "[connect-status] ${it.status}")
            ui {
                if (it.status != Status.SUCCESS) {
                    if (it.status == Status.DISCONNECTED_BY_DEVICE) {
                        Tips.show("设备侧主动断开了连接，将在3秒后自动关闭页面")
                        binding.loading.postDelayed({
                            finish()
                        }, 3000L)
                    } else if (it.status == Status.FAILED) {
                        binding.loading.gone()
                        binding.connect.visible()
                        binding.connect.text = "重试"
                        Tips.show("连接失败：$it")
                    } else {
                        binding.loading.visible()
                    }
                } else {
                    if (rendered) {
                        binding.loading.gone()
                    }


//                    binding.playerContainer.viewTreeObserver.addOnGlobalLayoutListener(object :
//                        ViewTreeObserver.OnGlobalLayoutListener {
//                        override fun onGlobalLayout() {
//                            // 移除监听避免重复调用
//                            binding.playerContainer.viewTreeObserver.removeOnGlobalLayoutListener(
//                                this
//                            )
//
//                            // 获取实际高度
//                            playerHeight = binding.playerContainer.height
//
//                            LogUtil.e("playerHeight:$playerHeight" + "width:" + binding.playerContainer.width)
//                        }
//
//                    })

                    binding.playerContainerParent.viewTreeObserver.addOnGlobalLayoutListener(object :
                        ViewTreeObserver.OnGlobalLayoutListener {
                        override fun onGlobalLayout() {
                            // 移除监听避免重复调用
                            binding.playerContainerParent.viewTreeObserver.removeOnGlobalLayoutListener(
                                this
                            )

                            // 获取实际高度
                            playerHeight = binding.playerContainerParent.height

                            LogUtil.e("playerHeight:$playerHeight" + "width:" + binding.playerContainerParent.width)
                        }

                    })



                    quueryDeviceAbilities()

                    queryStorageConfigure()
//                    queryFeeder()

                    queryRecordDay()
//                    queryRecord("2025-04-23")
                    queryRecord(DateUtil.getTodayDate())

                    handler.removeCallbacks(updateRecode)
                    handler.postDelayed(updateRecode, 60 * 1000)

//                    storageInstruction = StorageInstruction(deviceFacade)
//                    storageInstruction!!.state {
//                        LogUtil.e(GsonUtils.toJson(it.data))
//                    }
                }
            }
        }

        // 创建设备交互模块
        deviceFacade = DeviceFacade(deviceId).apply {
            if (lanMode) {
                mode = ConnectionMode.LANRTC
            }
//            enableLanMode(lanMode)

            // 监听连接状态变化
            observeConnectStatus(connectStatusObserver)

            lanSpecifyDeviceConsumer = Consumer { resp ->
                if (resp.success) {
                    val device = resp.data
                    if (device != null) {
                        SocketIoManager.launchLocalServiceByIp(baseContext, device.ip)
                    }
                }
            }
        }



        deviceFacade.connect()

        // 创建实时媒体数据源
        deviceLiveMediaSource = DeviceLiveMediaSource(deviceFacade).apply {
            onFrameRate = Consumer {
                val df = DecimalFormat("#.00")
                binding.frameRateLabel.text = "${df.format(it)} FPS"
            }

            onBitrate = Consumer {
                val df = DecimalFormat("#.00")
                binding.bitrateLabel.text = "${df.format(it)} kB/s"
            }
        }

        // 创建媒体播放器
        newLivePlay()

        binding.tvReplaceLive.onClicked {
            binding.loading.visible()

            deviceMediaRender.play(false)
            deviceStorageMediaSource!!.enableProduce(false)

            binding.playerContainer.visible()


            deviceMediaRender = DeviceMediaRender(this, deviceLiveMediaSource).apply {


                // 将播放器示例绑定到UI上
                attach(binding.playerContainer, createCenterLayoutParams())

                // 监听首帧数据渲染回调
                observeFirstFrameRendered {
                    rendered = true
                    binding.connect.gone()
                    binding.loading.gone()
                }
            }

//            newLivePlay()
            deviceMediaRender.play(true)
            deviceLiveMediaSource.enableProduce(true)

            deviceMediaRender.reset()

            binding.ivRecord.gone()
            binding.tvReplaceLive.gone()
            binding.tvTitle.text = "实时预览"
        }

        deviceMediaRender.onTimestampUpdate = Consumer {
            binding.playTimestamp.post {
//                if (binding.playTimestampLayout.visibility != View.VISIBLE) {
//                    binding.playTimestampLayout.visible()
//                }
                binding.playTimestamp.text = "Device UTC Time: ${DateUtil.getStrToTime(it)}"
                binding.playTimestampLayout.gone()
            }
        }

        binding.playTimestampLayout.gone()


        deviceMediaRender.onVideoDelayUpdate = Consumer {
            if (System.currentTimeMillis() - lastDelayUpdate > 1000) {
                lastDelayUpdate = System.currentTimeMillis()
                binding.videoDelayLabel.post {
                    binding.videoDelayLabel.text = "${it}s Delay"
                }
            }
        }

        // 监听录屏的状态
        deviceMediaRender.screenRecord().recordStatusObserver =
            object : DeviceScreenRecord.RecordStatusObserver {
                override fun onStart() {
                    Log.i(TAG, "[RecordStatusObserver][onStart] ")
                }

                override fun onDurationUpdate(duration: Long) {
                    Log.i(TAG, "[RecordStatusObserver][onDurationUpdate] $duration")
                }

                override fun onComplete(success: Boolean, path: String) {
                    Log.i(TAG, "[RecordStatusObserver][onComplete] $success")
                }


            }


        binding.loading.visible()
        binding.audio.setImageDrawable(
            ContextCompat.getDrawable(
                this,
                R.drawable.ic_baseline_volume_on_white
            )
        )
        binding.audio.onClicked { switchAudio() }
        binding.screenShot.gone()
        binding.screenShot.onClicked { screenshot() }
        binding.screenRecord.onClicked { screenRecord() }
        binding.screenRecord.gone()
        binding.talkBack.onClicked { talkback() }
        binding.fullScreen.onClicked { switchFullScreen() }
        binding.back.onClicked { finish() }
        binding.connect.onClicked {
            binding.connect.gone()
            deviceFacade.connect()
        }
        binding.localPlayback.onClicked { launchLocalPlayback() }
        binding.cloudPlayback.onClicked { launchCloudPlayback() }
        binding.cloudPlayback.gone()

        binding.resolutions.visible()
        binding.resolutions.gone()
//        binding.resolutions.onClicked { queryResolutions() }

//        binding.tvClarity.setOnClickListener {
//            queryResolutions()
//        }

        binding.vsbVolume.setOnProgressChangeListener(object :
            VerticalSeekBar.OnProgressChangeListener {
            override fun onProgressChanged(progress: Int) {
                Log.d("Progress", "当前进度：$progress")
            }
        })
        binding.vsbVolume.setMax(200)
        binding.vsbVolume.setProgress(75)

        binding.tvClarity.onClicked { queryResolutions(true) }

        binding.clRestart.onClicked {
            deviceFacade.instruct
                .create(TCI_CMD_DEV_REBOOT_REQ)
                .send {
                    if (it.success) {
                        it.data?.let {
                            ToastUtils.showShort("重启成功")
                        }
                    } else {
                        ToastUtils.showShort("重启失败")
                    }
                }
        }



        if (!lanMode) {
            DeviceInfoQuery.requireTimezone(deviceId) { resp ->

                // 请求设备时区，用于日期展示等用途（若设备不存在出海、手机与设备分处不同时区的场景，可忽略此步骤）
                resp.data?.format()?.let {
                    timeZone = it
                }
            }
        }

        handler.post(updateTask)


        binding.playerContainer.layoutParams = FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            width / 16 * 9.toInt()
        )

        binding.tvHd.isActivated = true
        binding.tvDeviceControl.isActivated = true

        binding.tvHd.onClicked {
            binding.tvHd.isActivated = true
            binding.tvSd.isActivated = false
            binding.tvDetail.isActivated = false
            binding.rvRecording.visible()
            binding.clDetail.gone()
            binding.tvTfTitle.text = "TF卡高清内容"
        }

        binding.tvSd.onClicked {
            binding.tvHd.isActivated = false
            binding.tvSd.isActivated = true
            binding.tvDetail.isActivated = false
            binding.rvRecording.visible()
            binding.clDetail.gone()
            binding.tvTfTitle.text = "TF卡标清内容"
        }

        binding.tvDetail.onClicked {
            binding.tvHd.isActivated = false
            binding.tvSd.isActivated = false
            binding.tvDetail.isActivated = true
            binding.rvRecording.gone()
            binding.clDetail.visible()
        }

        binding.tvDeviceControl.onClicked {
            binding.tvDeviceControl.isActivated = true
            binding.tvDeviceInfo.isActivated = false
            binding.llDeviceControl.visible()
            binding.svDeviceInfo.gone()
        }

        binding.tvDeviceInfo.onClicked {
            binding.tvDeviceControl.isActivated = false
            binding.tvDeviceInfo.isActivated = true
            binding.llDeviceControl.gone()
            binding.svDeviceInfo.visible()
        }


        binding.sv180.isShowOpenWarning = true
        binding.sv180.isShowClostWarning = true
        binding.sv180.setOnWarningListener { isSetOpen ->
            if (isSetOpen) {
                binding.sv180.isOpened = true
                deviceMediaRender.setRotation(DeviceMediaRender.Rotation.CW_180)
            } else {
                binding.sv180.isOpened = false
                deviceMediaRender.setRotation(DeviceMediaRender.Rotation.CW_0)
            }
        }

        LogUtil.e("AudioManager.STREAM_MUSIC:" + VolumeUtils.getMaxVolume(AudioManager.STREAM_MUSIC))
        LogUtil.e("AudioManager.STREAM_SYSTEM:" + VolumeUtils.getMaxVolume(AudioManager.STREAM_SYSTEM))
        LogUtil.e("AudioManager.STREAM_NOTIFICATION:" + VolumeUtils.getMaxVolume(AudioManager.STREAM_NOTIFICATION))
        binding.vsbVolume.setMax(VolumeUtils.getMaxVolume(AudioManager.STREAM_MUSIC))
        binding.vsbVolume.setProgress(VolumeUtils.getVolume(AudioManager.STREAM_MUSIC))

        setOnTouchOutsideViewListener1(binding.vsbVolume, object : OnTouchOutsideViewListener1 {
            override fun onTouchOutside(view: View, event: MotionEvent) {
                binding.llVolume.gone()
            }
        })

        mAdapter = object : LoadMoreAdapter<NewRecordingData>(
            R.layout.item_local_record
        ) {
            override fun convert(
                holder: BaseViewHolder,
                item: NewRecordingData
            ) {
                val rvRecord = holder.getView<RecyclerView>(R.id.rv_record)

                holder.setText(R.id.tv_tf_title, item.title)

                var mRecordAdapter = object : LoadMoreAdapter<RecordingData>(
                    R.layout.item_local_record_child
                ) {
                    override fun convert(
                        holder: BaseViewHolder,
                        item: RecordingData
                    ) {
                        //yyyy-MM-dd
                        val startTime = millis2String(
                            item.recodeData.start,
                            SimpleDateFormat("HH:mm:ss")
                        )

                        val endTime = millis2String(
                            item.recodeData.end,
                            SimpleDateFormat("HH:mm:ss")
                        )

                        val tvTime = holder.getView<TextView>(R.id.tv_time)
                        tvTime.text = "$startTime~$endTime"

                        val ivVideo = holder.getView<ImageView>(R.id.iv_video)
                        ivVideo.setOnClickListener {
                            playRecord(
                                item.recodeData,
                                ivVideo,
                                holder.adapterPosition
                            )
                        }

                        val pbDownload = holder.getView<ProgressBar>(R.id.pb_download)


                        val ivDownload = holder.getView<ImageView>(R.id.iv_download)
                        ivDownload.setOnClickListener {
                            goToDownloadRecord(item.recodeData, pbDownload)
                        }
                        val ivPic = holder.getView<ImageView>(R.id.iv_pic)

//                        if (!TextUtils.isEmpty(item.pic)) {
//                            val bytes: ByteArray =
//                                Base64.decode(item.pic, Base64.DEFAULT)
//                            val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
//                            ivPic.setImageBitmap(bitmap)
//                        } else {
//                            ivPic.setImageResource(0)
//                        }

                        if (item.file != null) {
                            Glide.with(ivPic.context)
                                .load(item.file)
                                .into(ivPic)
                        } else {
                            ivPic.setImageResource(0)
                        }
                    }
                }

                rvRecord.layoutManager =
                    LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
                rvRecord.adapter = mRecordAdapter
                mRecordAdapter.setNewInstance(item.recordData)
            }
        }

        binding.rvRecording.layoutManager = LinearLayoutManager(this)
        binding.rvRecording.adapter = mAdapter


        binding.tvTest.onClicked {
            //
            queryRecordDay()
        }
    }

    private var disposable: Disposable? = null


    @SuppressLint("CheckResult")
    private fun goToDownloadRecord(item: DeviceStoragePlayback.Index, pbDownload: ProgressBar) {
        if (!XXPermissions.isGranted(
                baseContext,
                Permission.READ_MEDIA_IMAGES,
                Permission.READ_MEDIA_VIDEO
            )
        ) {
            requestPermission(item, pbDownload)
        } else {
            checkDownload(item, pbDownload)
        }
    }

    private fun Long.toByteArray(): ByteArray {
        // 分配 8个字节的缓冲区
        val buffer = ByteBuffer.allocate(Long.SIZE_BYTES) // Long.SIZE_BYTES 就是 8
        // 默认是大端序 (BIG_ENDIAN)
        buffer.order(ByteOrder.LITTLE_ENDIAN)
        buffer.putLong(this)
        return buffer.array()
    }

    private var count = 0

    @SuppressLint("CheckResult")
    private fun checkDownload(item: DeviceStoragePlayback.Index, pbDownload: ProgressBar) {
        val yourByteArray: ByteArray = (item.start / 1000L).toByteArray()


        deviceFacade.instruct
            .create(TCI_CMD_DEV_DOWNLOAD_REQ)
            .data(yourByteArray)
            .send {
                if (it.success) {
                    LogUtil.e(GsonUtils.toJson(String(it.data!!)))
                    val string =
                        java.lang.String(it.data!!.takeWhile { it != 0.toByte() }.toByteArray())
                            .toString()

                    val wifiEnabled = NetworkUtils.getWifiEnabled()
                    if (wifiEnabled){
                        val targetWifiInScanResults =
                            isTargetWifiInScanResults(this, "GNSSA_1E4EF5")
                        val isTargetWifi = isConnectedToTargetWifi(this, "GNSSA_1E4EF5")
                        if (isTargetWifi){2
                            downloadVideo(string.trim(), item, pbDownload)
                        } else {
                            if (targetWifiInScanResults){
                                connectToWifi(string, item, pbDownload, TYPE_DOWNLOAD_VIDEO, null)
                            } else {
                                ToastUtils.showShort( "未搜索到设备热点，请重启设备")
                            }
                        }
                    } else {
//                      WifiUtils.requestEnableWifi(this)
                        NetworkUtils.setWifiEnabled(true)
                        ToastUtils.showShort("请打开wifi连接设备热点")
                    }




//                    downloadVideo(string,item, pbDownload)
                } else {
                    ToastUtils.showShort("下载失败，请重试")
                }
            }

        return
        //测试数据
        val url1 = "https://www.sample-videos.com/video321/mp4/720/big_buck_bunny_720p_30mb.mp4"
        val url2 = "https://www.sample-videos.com/video321/mp4/480/big_buck_bunny_480p_30mb.mp4"


        if (count == 0) {
            count++
            url1.download()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeBy(
                    onNext = {
                        LogUtil.e(url1.file().name + ":" + it.percentStr())

                        pbDownload.run {
                            pbDownload.progress = it.percent().toInt()
                        }
                    },
                    onComplete = {
                        LogUtil.e("完成")

                        val file = url1.file()
                        LogUtil.e(file.absolutePath)
                    },
                    onError = {
                        LogUtil.e("失败")
                    }
                )
        } else {
            url2.download()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeBy(
                    onNext = {
                        LogUtil.e(url2.file().name + ":" + it.percentStr())

                        pbDownload.run {
                            pbDownload.progress = it.percent().toInt()
                        }
                    },
                    onComplete = {
                        LogUtil.e("完成")

                        val file = url2.file()
                        LogUtil.e(file.absolutePath)
                    },
                    onError = {
                        LogUtil.e("失败")
                    }
                )
        }
    }

    private fun refreshMediaLibrary(context: Context, filePath: String) {
        val file = File(filePath)
        if (file.exists()) {
            val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
            val uri = Uri.fromFile(file)
            context.sendBroadcast(intent)

            // 或者使用 MediaScannerConnection
            MediaScannerConnection.scanFile(
                context,
                arrayOf(filePath),
                null
            ) { path, uri ->
                LogUtil.e("文件已刷新，URI: $uri")
            }
        } else {
            LogUtil.e("文件不存在，无法刷新媒体库")
        }
    }

    private var isDownloading = false
    private var isDownloadingJpg = false

    @SuppressLint("CheckResult")
    private fun downloadJpg(
        url: String,
        timestamp: Long
    ) {
        if (isDownloadingJpg) {
            ToastUtils.showShort("正在下载，请稍等")
            return
        }
        isDownloadingJpg = true
        url.download()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeBy(
                onNext = {
                    LogUtil.e(url.file().name + ":" + it.percentStr())
                },
                onComplete = {
                    LogUtil.e("完成")

                    val file = url.file()
//                    MediaSaver.saveMp4ToGallery(baseContext, file, "jscx")
                    val cacheFileManager = CacheFileManager()
                    cacheFileManager.copyFileToCache(baseContext, file, file.name)

                    for (beanData in handleRecordData!!) {
                        for (childBeanData in beanData.recordData) {
                            if (childBeanData.recodeData.start / 1000 == timestamp) {
                                childBeanData.file =  file
                            }
                        }
                    }

                    mAdapter!!.notifyDataSetChanged()
                    isDownloadingJpg = false
                    checkJpg()
                },
                onError = {
                    LogUtil.e("失败")
                    isDownloadingJpg = false
                }
            )
    }

    @SuppressLint("CheckResult")
    private fun downloadVideo(
        url: String,
        item: DeviceStoragePlayback.Index,
        pbDownload: ProgressBar
    ) {
        if (isDownloading) {
            ToastUtils.showShort("正在下载，请稍等")
            return
        }
        isDownloading = true
//        var urlTest = "http://192.168.183.4:8088/camera0_default_20250619/h265_1750316917_150837_301.mp4"
        url.download()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeBy(
                onNext = {
                    LogUtil.e(url.file().name + ":" + it.percentStr())
                    pbDownload.run {
                        pbDownload.progress = it.percent().toInt()
                    }
                },
                onComplete = {
                    LogUtil.e("完成")

                    val file = url.file()
                    LogUtil.e(file.absolutePath)

                    MediaSaver.saveMp4ToGallery(baseContext, file, "jscx")
                    isDownloading = false
                },
                onError = {
                    LogUtil.e("失败")
                    isDownloading = false
                }
            )
    }

    private fun requestPermission(item: DeviceStoragePlayback.Index, pbDownload: ProgressBar) {
        XXPermissions.with(this) // 申请单个权限
            .permission(Permission.READ_MEDIA_IMAGES)
            .permission(Permission.READ_MEDIA_VIDEO)
            //.interceptor(new PermissionInterceptor())
            // 设置不触发错误检测机制（局部设置）
            //.unchecked()
            .request(object : OnPermissionCallback {

                override fun onGranted(permissions: List<String?>, allGranted: Boolean) {
                    if (!allGranted) {
                        return
                    }
                    LogUtil.e("获取READ_MEDIA权限成功")
                    checkDownload(item, pbDownload)
                }

                override fun onDenied(permissions: List<String?>, doNotAskAgain: Boolean) {
                    if (doNotAskAgain) {
                        LogUtil.e("被永久拒绝授权")
                        // 如果是被永久拒绝就跳转到应用权限系统设置页面
                        runOnUiThread {

                            var normalMsgDialog =
                                NormalMsgVPopup(baseContext)
                            normalMsgDialog.showPopupWindow()
                            normalMsgDialog.tvTitle.text = "温馨提示"
                            normalMsgDialog.tvContent.text =
                                "权限被禁止了需要手动开启"
                            normalMsgDialog.tvCancel.visibility = View.VISIBLE
                            normalMsgDialog.tvCancel.text = "取消"
                            normalMsgDialog.tvSure.text = "确定"
                            normalMsgDialog.tvSure.onClicked {
                                normalMsgDialog.dismiss()
                                try {
                                    XXPermissions.startPermissionActivity(
                                        this@DeviceLiveActivity,
                                        permissions
                                    )
                                } catch (e: java.lang.Exception) {
                                    // 处理异常，例如在非Activity的Context中使用
                                }
                            }
                        }

                    } else {
                        LogUtil.e("获取READ_MEDIA权限失败")
                    }
                }
            })

    }

    private fun newLivePlay() {
        deviceMediaRender = DeviceMediaRender(this, deviceLiveMediaSource).apply {

            if (AudioRecorder.FORCE_MODE_IN_COMMUNICATION) {
                TGLog.i(TAG, "[onCreate] FORCE_MODE_IN_COMMUNICATION")
                audioOutputChannel = AudioMode.MODE_IN_COMMUNICATION
            }

            mute(false)

            // 将播放器示例绑定到UI上
            attach(binding.playerContainer, createCenterLayoutParams())

            // 监听首帧数据渲染回调
            observeFirstFrameRendered {
                TGLog.i(TAG, "[first-rendered] ")
                rendered = true
                binding.loading.gone()
                binding.tvClarity.visible()
                queryResolutions(false)
                binding.opButtons.visible()
            }
            binding.videoChatControl.gone()
        }

    }

    private var deviceStorageMediaSource: DeviceStorageMediaSource? = null

    private fun playRecord(
        item: DeviceStoragePlayback.Index,
        ivVideo: ImageView,
        adapterPosition: Int
    ) {
        if (deviceStorageMediaSource == null) {
            deviceStorageMediaSource = DeviceStorageMediaSource(deviceFacade).apply {
                productionMode = DeviceStorageMediaSource.ProductionMode.SINGLE
                onReceiveNextPart = Consumer {
                    Tips.show("开始播放：${DateUtil.getStrToTime(it)}")
                }
            }
        }

        // 创建媒体播放器
        deviceMediaRenderRecode = DeviceMediaRender(this, deviceStorageMediaSource!!).apply {

            // 将播放器示例绑定到UI上
            attach(binding.playerContainerRecode, createCenterLayoutParams())

            // 监听首帧数据渲染回调
            observeFirstFrameRendered {
                rendered = true
                binding.connect.gone()
                binding.loading.gone()
            }
        }

        binding.loading.visible()

        binding.playerContainerParent.layoutParams.height = playerHeight
        binding.playerContainer.invisible()


        deviceLiveMediaSource.enableProduce(false)
        deviceMediaRender.play(false)

        deviceStorageMediaSource!!.seek(item.start)
        deviceMediaRenderRecode.reset()

        binding.ivRecord.visible()
        binding.tvReplaceLive.visible()
        binding.tvTitle.text = "录像"
    }

    private fun playAnim() {
        val fadeOut = ObjectAnimator.ofFloat(binding.ivRecord, "alpha", 1f, 0f)
        fadeOut.setDuration(1000); // 持续1秒
        fadeOut.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                super.onAnimationEnd(animation)
            }
        })

        val fadeIn = ObjectAnimator.ofFloat(binding.ivRecord, "alpha", 0f, 1f)
        fadeIn.setDuration(1000) // 持续1秒
        fadeIn.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationStart(animation: Animator) {
            }
        })

        val animatorSet = AnimatorSet()
        animatorSet.playSequentially(fadeOut, fadeIn)
        animatorSet.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                animatorSet.start() // 动画结束后重新开始，实现循环
            }
        })
        animatorSet.start()

        val fadeOut1 = ObjectAnimator.ofFloat(binding.tvReplaceLive, "alpha", 1f, 0f)
        fadeOut1.setDuration(1000); // 持续1秒
        fadeOut1.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                super.onAnimationEnd(animation)
            }
        })

        val fadeIn1 = ObjectAnimator.ofFloat(binding.tvReplaceLive, "alpha", 0f, 1f)
        fadeIn1.setDuration(1000) // 持续1秒
        fadeIn1.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationStart(animation: Animator) {
            }
        })

        val animatorSet1 = AnimatorSet()
        animatorSet1.playSequentially(fadeOut1, fadeIn1)
        animatorSet1.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                animatorSet1.start() // 动画结束后重新开始，实现循环
            }
        })
        animatorSet1.start()
    }

    private var handleRecordData: ArrayList<NewRecordingData>? = null
    private var oldAllRecode: ArrayList<RecordingData>? = null

    private val STR_15_MIN = "15分钟以内"
    private val STR_30_MIN = "30分钟以内"
    private val STR_OTHER_MIN = "其他"
    private fun queryRecord(date: String) {
        ui {
            // 反复查询不同日期，应当使用同一个实例，而非每次都new一个！
            if (playbackQuery == null) {
                playbackQuery = DeviceStoragePlayback(deviceFacade)
            }

            if (oldAllRecode == null) {
                oldAllRecode = ArrayList<RecordingData>()
            }

            if (handleRecordData == null) {
                handleRecordData = ArrayList<NewRecordingData>()
                handleRecordData!!.add(
                    NewRecordingData(
                        STR_15_MIN,
                        ArrayList<RecordingData>()
                    )
                )
                handleRecordData!!.add(
                    NewRecordingData(
                        STR_30_MIN,
                        ArrayList<RecordingData>()
                    )
                )
                handleRecordData!!.add(
                    NewRecordingData(
                        STR_OTHER_MIN,
                        ArrayList<RecordingData>()
                    )
                )
            }

            playbackQuery?.query(date) {
                ui {
                    LogUtil.e("录像数据：" + GsonUtils.toJson(it.data))

                    binding.loading.gone()
                    if (it.success) {


                        for (i in handleRecordData!!.size - 1 downTo 0) {
                            for (j in handleRecordData!![i].recordData.size - 1 downTo 0) {
                                var isExist = false
                                for (oldBean in oldAllRecode!!) {
                                    if (oldBean.recodeData.start == handleRecordData!![i].recordData[j].recodeData.start) {
                                        isExist = true
                                    }
                                }
                                if (!isExist) {
                                    oldAllRecode!!.add(handleRecordData!![i].recordData[j])
                                }
                            }
                        }


                        if (it.data != null && it.data!!.isNotEmpty()) {
                            for (i in oldAllRecode!!.size - 1 downTo 0) {
                                for (j in it.data!!.indices.reversed()) {
                                    if (oldAllRecode!![i].recodeData.start == it.data!![j].start) {
                                        (it.data as ArrayList).removeAt(j)
                                    }
                                }
                            }

                            LogUtil.e(GsonUtils.toJson(it.data))

                            handleRecordData!![0].recordData.clear()
                            handleRecordData!![1].recordData.clear()
                            handleRecordData!![2].recordData.clear()

                            for (index in it.data!!.size - 1 downTo 0) {
                                var bean = it.data!![index]
                                if (System.currentTimeMillis() - bean.start < 15 * 60 * 1000) {
                                    val recordingData = RecordingData()
                                    recordingData.recodeData = bean
                                    handleRecordData!![0].recordData.add(recordingData)
                                } else if (System.currentTimeMillis() - bean.start < 30 * 60 * 1000) {
                                    val recordingData = RecordingData()
                                    recordingData.recodeData = bean
                                    handleRecordData!![1].recordData.add(recordingData)
                                } else {
                                    val recordingData = RecordingData()
                                    recordingData.recodeData = bean
                                    handleRecordData!![2].recordData.add(recordingData)
                                }
                            }

                            for (index in oldAllRecode!!.size - 1 downTo 0) {
                                var bean = oldAllRecode!![index].recodeData
                                if (System.currentTimeMillis() - bean.start < 15 * 60 * 1000) {
                                    val recordingData = RecordingData()
                                    recordingData.recodeData = bean
                                    recordingData.pic = oldAllRecode!![index].pic
                                    handleRecordData!![0].recordData.add(recordingData)
                                } else if (System.currentTimeMillis() - bean.start < 30 * 60 * 1000) {
                                    val recordingData = RecordingData()
                                    recordingData.recodeData = bean
                                    recordingData.pic = oldAllRecode!![index].pic
                                    handleRecordData!![1].recordData.add(recordingData)
                                } else {
                                    val recordingData = RecordingData()
                                    recordingData.recodeData = bean
                                    recordingData.pic = oldAllRecode!![index].pic
                                    handleRecordData!![2].recordData.add(recordingData)
                                }
                            }
                        }

                        //todo
                        checkJpg()

                        runOnUiThread {
                            mAdapter!!.setList(handleRecordData)
                        }


//                        binding.list.scrollToPosition(0)
//                        it.data?.let { listAdapter.refresh(it) }


                    } else {
                        if (DeviceStoragePlayback.ERROR_NO_RECORD == it.code) {
//                            binding.emptyView.visible()
                        } else {
//                            binding.emptyView.visible()
//                            binding.emptyView.text = "错误：${it.code}, ${it.message}"
                        }
                    }
                }
            }
        }

        playAnim()
    }

    fun isTargetWifiInScanResults(context: Context, targetSsid: String): Boolean {
        val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

        // 检查权限和位置服务是否开启
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!wifiManager.isScanAlwaysAvailable) {
                // 扫描功能不可用
                return false
            }
        }

        return try {
            val scanResults = wifiManager.scanResults
            scanResults.any { scanResult ->
                scanResult.SSID?.removeSurrounding("\"") == targetSsid
            }
        } catch (e: SecurityException) {
            // 处理权限异常
            false
        }
    }

    private fun checkJpg() {
        if (handleRecordData == null || handleRecordData!!.isEmpty()) return
        // 已连接到目标 Wi-Fi
        outerLoop@ for (bean in handleRecordData!!) {
            for (childBean in bean.recordData) {
//                if (TextUtils.isEmpty(childBean.pic)) {
                if (childBean.file == null) {
                    val littleEndianBytes1 =
                        HexConverter.toLittleEndianBytes(childBean.recodeData.start / 1000, 4)
                    val littleEndianBytes2 =
                        HexConverter.toLittleEndianBytes(childBean.recodeData.end / 1000, 4)
                    var littleEndianBytes = littleEndianBytes1 + littleEndianBytes2

                    deviceFacade.instruct
                        .create(TCI_CMD_DEV_JPG_REQ)
                        .data(littleEndianBytes)
                        .send {
                            if (it.success) {
                                val json: String = ResponseParser.parseToJson(it.data!!)
                                val data = GsonUtils.fromJson<JpgBeanV2>(
                                    json,
                                    object : TypeToken<JpgBeanV2>() {}.type
                                )

                                var downloadJpgUrl = ""
                                var timestamp = 0L
                                for (beanData in handleRecordData!!) {
                                    for (childBeanData in beanData.recordData) {
                                        for (jpgBean in data.thumbnails) {
                                            if (childBeanData.recodeData.start / 1000 == jpgBean.timestamp) {
                                                downloadJpgUrl = jpgBean.url
                                                timestamp = jpgBean.timestamp
                                            }
                                        }
                                    }
                                }

                                val wifiEnabled = NetworkUtils.getWifiEnabled()
                                if (wifiEnabled){
                                    val targetWifiInScanResults =
                                        isTargetWifiInScanResults(this, "GNSSA_1E4EF5")
                                    val isTargetWifi = isConnectedToTargetWifi(this, "GNSSA_1E4EF5")
                                    if (isTargetWifi){
                                        downloadJpg(downloadJpgUrl,timestamp)
                                    } else {
                                        if (targetWifiInScanResults){
                                            connectToWifi(downloadJpgUrl, null, null, TYPE_DOWNLOAD_JPG,timestamp)
                                        } else {
                                            ToastUtils.showShort( "未搜索到设备热点，请重启设备")
                                        }
                                    }
                                } else {
                                    WifiUtils.requestEnableWifi(this)
//                                    NetworkUtils.setWifiEnabled(true)
                                    ToastUtils.showShort("请打开wifi连接设备热点")
                                }

//                                val resp =
//                                    VrThumbnailParser.parse(it.data!!)
//                                val json = JsonConverter.toJson(resp)
//                                val data = GsonUtils.fromJson<JpgBean>(
//                                    json,
//                                    object : TypeToken<JpgBean>() {}.type
//                                )
//                                for (beanData in handleRecordData!!) {
//                                    for (childBeanData in beanData.recordData) {
//                                        for (jpgBean in data.thumbnails) {
//                                            if (childBeanData.recodeData.start / 1000 == jpgBean.timestamp) {
//                                                childBeanData.pic = jpgBean.data
//                                            }
//                                        }
//                                    }
//                                }

//                                mAdapter!!.notifyDataSetChanged()
//                                checkJpg()
                            } else {

                            }
                        }
                    break@outerLoop
                }
            }
        }





        return


        val littleEndianBytes1 = HexConverter.toLittleEndianBytes(1750400059L, 4)
        val littleEndianBytes2 = HexConverter.toLittleEndianBytes(1750400065L, 4)
        var littleEndianBytes = littleEndianBytes1 + littleEndianBytes2


        deviceFacade.instruct
            .create(TCI_CMD_DEV_JPG_REQ)
            .data(littleEndianBytes)
            .send {
                if (it.success) {
                    val resp =
                        VrThumbnailParser.parse(it.data!!)
                    val json = JsonConverter.toJson(resp)
                    LogUtils.e("数据：", json)
                } else {
                    ToastUtils.showShort("下载失败，请重试")
                }
            }
    }

    private fun queryRecordDay() {
        // 反复查询不同日期，应当使用同一个实例，而非每次都new一个！
        if (playbackQuery == null) {
            playbackQuery = DeviceStoragePlayback(deviceFacade)
        }
        playbackQuery!!.queryRecordDays {
            ui {
                if (it.success) {
                    it.data?.let { list ->
                        LogUtil.i("查询录像日期：${list}")
                        checkJpg()
                    }
                } else {
                    Tips.show("查询录像日期失败：${it.message}")
                }
            }

        }
    }


    private fun formatSpeed(speed: Double): String {
        return if (speed < 1024) {
            String.format(Locale.getDefault(), "%.2f B/s", speed)
        } else if (speed < 1024 * 1024) {
            String.format(Locale.getDefault(), "%.2f KB/s", speed / 1024)
        } else {
            String.format(Locale.getDefault(), "%.2f MB/s", speed / (1024 * 1024))
        }
    }

    private val handler: Handler = Handler()
    private var lastUpdateTime: Long = 0
    private var lastRxBytes: Long = 0
    private var lastTxBytes: Long = 0

    private val updateTask: Runnable = object : Runnable {
        override fun run() {
            val currentRxBytes = TrafficStats.getTotalRxBytes()
            val currentTxBytes = TrafficStats.getTotalTxBytes()
            val currentTime = System.currentTimeMillis()

            // 处理设备不支持的情况
            if (currentRxBytes == TrafficStats.UNSUPPORTED.toLong() || currentTxBytes == TrafficStats.UNSUPPORTED.toLong()) {
                binding.tvInternetSpeed.text = "网速监测不可用"

                handler.postDelayed(this, 1000)
                return
            }

            // 计算时间差（毫秒）
            var timeDiff: Long = currentTime - lastUpdateTime
            if (timeDiff == 0L) timeDiff = 1 // 避免除零


            // 计算速度（字节/秒）
            val downloadSpeed: Double = (currentRxBytes - lastRxBytes) * 1000.0 / timeDiff
            val uploadSpeed: Double = (currentTxBytes - lastTxBytes) * 1000.0 / timeDiff

            // 更新上一次记录
            lastRxBytes = currentRxBytes
            lastTxBytes = currentTxBytes
            lastUpdateTime = currentTime

            // 格式化速度文本
            val download = formatSpeed(downloadSpeed)
            val upload = formatSpeed(uploadSpeed)
            val speedText = download

            // 更新界面
            binding.tvInternetSpeed.setText(speedText)

            // 每秒执行一次
            handler.postDelayed(this, 1000)
        }
    }

    private val updateRecode: Runnable = object : Runnable {
        override fun run() {
            queryRecord(DateUtil.getTodayDate())
            handler.postDelayed(this, 60 * 1000)
        }
    }

    private fun queryFeeder() {
        var feeder = FeederInstruction(deviceFacade)
        feeder.current {
            if (it.success) {
                val maxTimers = it.data?.maxTimers ?: 0
                val maxServings = it.data?.maxServings ?: 0
                TGLog.i(
                    TAG,
                    "[queryFeeder] [current] maxTimers = $maxTimers, maxServings = $maxServings"
                )
            } else {
                TGLog.i(TAG, "[queryFeeder] [current] error = ${it.message}")
            }
        }
        feeder.currentPlans() {
            if (it.success) {
                val plans = it.data
                TGLog.i(TAG, "[queryFeeder] [currentPlans] plans = $plans")
                if (plans != null) {
                    plans.get(0)?.let {
                        TGLog.i(TAG, "[queryFeeder] plan = $it")
                        it.time.hour = 12
                        feeder.updatePlans(plans) {
                            if (it.success) {
                                TGLog.i(TAG, "[queryFeeder] [updatePlans] success")
                            } else {
                                TGLog.i(
                                    TAG,
                                    "[queryFeeder] [updatePlans] error = ${it.message}"
                                )
                            }
                        }
                    }
                }

            } else {
                TGLog.i(TAG, "[queryFeeder] [currentPlans] error = ${it.message}")
            }
        }
        feeder.feed(1) {
            if (it.success) {
                TGLog.i(TAG, "[queryFeeder][feed]  success")
            } else {
                TGLog.i(TAG, "[queryFeeder][feed] error = ${it.message}")
            }
        }
    }

    private fun queryStorageConfigure() {
        deviceFacade.instruct
            .create(INSTRUCTION_DEV_INFO_REQ)
            .send {
                if (it.success) {
                    it.data?.let {
                        val totalSize = Packet.byteArrayToInt_Little(it, 40)
                        hasSdCard = totalSize > 0
                        if (hasSdCard) {
                            //隐藏录像
                            binding.localPlayback.post {
                                binding.localPlayback.visible()
                            }
                        }
                    }
                } else {
                    Tips.show("查询设备信息失败")
                }
            }
    }

    private fun quueryDeviceAbilities() {

        BasicInstruction(deviceFacade).queryProperties {
            it.data?.abilities?.let {

                if (it.containsKey("Microphone") && (it["Microphone"] ?: "").isNotEmpty()) {
                    val configure = it["Microphone"] ?: ""
                    deviceSupportAec = configure.lowercase(Locale.getDefault()).contains("aec")
                    TGLog.i(TAG, "[queryScreenConfigure] Microphone.configure = $configure")
                }

                if (it.containsKey("Screen") && (it["Screen"] ?: "").isNotEmpty()) {
                    val configure = it["Screen"] ?: ""

                    TGLog.i(TAG, "[queryScreenConfigure] configure = $configure")

                    val segments = configure.split(":")
                    val encodingFormat = if (segments.size > 0) segments[0] else "h264"
                    val resolution = if (segments.size > 1) segments[1] else "320x240"
                    val widthAndHeight = resolution.split("x")
                    val width = widthAndHeight.getOrNull(0)?.toIntOrNull() ?: 320
                    val height = widthAndHeight.getOrNull(1)?.toIntOrNull() ?: 240
                    val codecType =
                        if (encodingFormat == "h264") CodecType.AVC else CodecType.MJPEG

                    LogUtil.e("[queryScreenConfigure] width = $width")
                    LogUtil.e("[queryScreenConfigure] height = $height")
                    LogUtil.e("[queryScreenConfigure] codecType = $codecType")

                    ui {
                        binding.screenAbility.text = "${codecType}, $resolution"
                    }

                    if (mediaCaptor == null) {
                        TGLog.i(TAG, "[queryScreenConfigure] create mediaCaptor")
                        videoChatPreviewConfigure(codecType, width, height)
                    }
                } else {
                    TGLog.i(TAG, "[queryScreenConfigure] not configured.")
                    videoChatPreviewConfigure(null, 320, 240)
                }
            }
        }
    }

    private fun videoChatPreviewConfigure(
        codecType: CodecType?,
        specifyWidth: Int,
        specifyHeight: Int
    ) {
        videoCaptureConfigure = VideoCaptureConfigure(CameraId.FACING_BACK).apply {
            width = specifyWidth
            height = specifyHeight
        }

        if (codecType != null) {

            binding.videoChatBtn.visible()

            binding.videoChatCamera.onClicked {
                if (mediaCaptor?.videoCapturing == true) {
                    binding.videoChatPreviewContainer.gone()
                    binding.videoChatCover.gone()
                    mediaCaptor!!.stopCaptureVideo()
                    if (videoCaptureConfigure!!.cameraId == CameraId.FACING_FRONT) {
                        videoCaptureConfigure =
                            VideoCaptureConfigure(CameraId.FACING_BACK).apply {
                                width = specifyWidth
                                height = specifyHeight
                            }
                    } else {
                        videoCaptureConfigure =
                            VideoCaptureConfigure(CameraId.FACING_FRONT).apply {
                                width = specifyWidth
                                height = specifyHeight
                            }
                    }
                    if (!deviceFacade.connected()) {
                        Tips.show("设备未连接！")
                        return@onClicked
                    }
                    videoCaptureConfigure?.let {
                        binding.videoChatPreviewContainer.visible()
                        binding.videoChatCover.visible()
                        mediaCaptor!!.startCaptureVideo(it)
                    }
                }
            }
            binding.videoChat.onClicked {

                if (!deviceFacade.connected()) {
                    Tips.show("设备未连接！")
                    return@onClicked
                }

                videoCaptureInternal()
            }
        }

        mediaCaptor =
            MediaCaptor(deviceFacade, applicationContext, codecType ?: CodecType.AVC).apply {

                if (ROTATE_90_ON_CAPTURE) {
                    // 若设备由于“屏幕安装角度”等原因，需要我们提前旋转画面，可自行注入图像处理器
                    videoCaptor.imageProcessors().add(RotationProcessor(90))
                    // 由于上方通过 RotationProcessor 旋转了画面，本地预览需要进行相应逆向旋转
                    videoCaptor.rotationOnPreview = VideoCapture.PreviewRotation.CW_270
                }

                videoCaptor.attachPreview(
                    binding.videoChatPreviewContainer,
                    createCenterLayoutParams()
                )

                onTalkbackState = Consumer {
                    ui {
                        if (it.success) {
                            // 注意： 若设备不支持AEC，即不支持双向对讲，那么 APP 侧 需要在对讲的时候同时 关闭 来自设备的音频
                            if (!deviceSupportAec) {
                                if (AudioRecorder.FORCE_MODE_IN_COMMUNICATION) { // FORCE_MODE_IN_COMMUNICATION 是调试专用，默认为false，一般情况你无需关心
                                    Tips.show("对讲开启成功\n已强制启用客户端AEC")
                                } else {
                                    Tips.show("对讲开启成功\n设备不支持AEC，暂关闭音频播放")
                                    muteAudio()
                                }
                            } else {
                                if (AudioRecorder.FORCE_MODE_IN_COMMUNICATION) { // FORCE_MODE_IN_COMMUNICATION 是调试专用，默认为false，一般情况你无需关心
                                    Tips.show("双向对讲开启成功\n已强制启用客户端AEC")
                                } else {
                                    Tips.show("双向对讲开启成功\n已根据能力配置启用客户端AEC")
                                }
                            }
                            if (mediaCaptor?.audioCapturing == true) {
                                binding.talkBack.setImageDrawable(
                                    ContextCompat.getDrawable(
                                        this@DeviceLiveActivity,
                                        R.drawable.ic_baseline_mic_on_24
                                    )
                                )
                            }
                        } else {
                            Tips.show("对讲开启失败：${it.message}")
                            stopVideoCapture()
                            stopCaptureAudio()
                            binding.talkBack.setImageDrawable(
                                ContextCompat.getDrawable(
                                    this@DeviceLiveActivity,
                                    R.drawable.ic_baseline_mic_off_24
                                )
                            )
                        }
                    }
                }

                videoCaptor.videoCaptureListener = object : CaptureObserver {
                    override fun onError(code: Int, message: String) {
                        ui { Tips.show("视频采集异常：$code, $message") }
                    }

                    override fun onInitialFramePrepared(size: Pair<Int, Int>) {
                        fileName = DateUtil.getCurrentTime() + ".h254"
                        TGLog.d(
                            TAG,
                            "[videoChatPreviewConfigure] VideoFrame onInitialFramePrepared "
                        )
                    }

                    override fun onPrepared(frame: VideoFrame) {

//                    FileUtil.wirteFile(fileName,frame.buffer)
                        TGLog.d(
                            TAG,
                            "[videoChatPreviewConfigure] VideoFrame codecType:${frame.codecType} keyFrame: ${frame.keyFrame} timestampMs: ${frame.timestampMs} "
                        )
                    }
                }

                val audioMode =
                    if (deviceSupportAec) AudioMode.MODE_IN_COMMUNICATION else AudioMode.MODE_NORMAL
                TGLog.i(TAG, "[videoChatPreviewConfigure] audioMode = $audioMode")

                if (deviceSupportAec) {
                    deviceMediaRender.audioOutputChannel = AudioMode.MODE_IN_COMMUNICATION
                    TGLog.i(TAG, "[videoChatPreviewConfigure] SET RENDER AEC")
                }

                audioCaptor.apply {

                    mode = audioMode

                    observeStatus {

                    }
                }
            }

    }

    private fun videoCaptureInternal() {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.CAMERA
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                this.requestPermissions(arrayOf(Manifest.permission.CAMERA), 100)
            }
            Tips.show("赋予摄像头权限后重试")
            return
        }

        if (mediaCaptor?.videoCapturing == true) {
            stopVideoCapture()
            binding.videoChatCameraBtn.gone()
        } else {
            startVideoCapture()
            binding.videoChatCameraBtn.visible()
        }
    }

    private fun startVideoCapture() {
        binding.videoChat.setImageDrawable(
            ContextCompat.getDrawable(
                this,
                R.drawable.ic_video_chat_on
            )
        )
        binding.videoChatPreviewContainer.visible()
        binding.screenAbility.visible()
        binding.videoChatCover.visible()
        videoCaptureConfigure?.let { mediaCaptor?.startCaptureVideo(it) }
    }

    private fun stopVideoCapture() {
        binding.videoChat.setImageDrawable(
            ContextCompat.getDrawable(
                this,
                R.drawable.ic_video_chat_off
            )
        )
        binding.videoChatPreviewContainer.gone()
        binding.screenAbility.gone()
        binding.videoChatCover.gone()
        mediaCaptor?.stopCaptureVideo()
    }

    private fun queryResolutions(isShow: Boolean) {
        if (!deviceMediaRender.playing) {
            Tips.show("当前未在播放！")
            return
        }

        if (!deviceFacade.connected()) {
            Tips.show("设备未连接！")
            return
        }

        deviceLiveMediaSource.querySupportedResolutions {
            Log.i(TAG, "[queryResolutions] $it")
            ui {
                if (it.success) {
                    val resolutions = it.data!!
                    val currentResolution = deviceLiveMediaSource.currentVideoResolution()
                    var currentIndex = 0

                    resolutions.forEachIndexed { index, liveResolutions ->
                        if (liveResolutions.value == currentResolution) {
                            currentIndex = index
                            if ("SD" == liveResolutions.label) {
                                binding.tvClarity.text = "标清"
                            } else if ("FHD" == liveResolutions.label) {
                                binding.tvClarity.text = "高清"
                            }
                        }
                    }


                    val items =
                        Array(resolutions.size) { index -> if (index == currentIndex) "${resolutions[index].label + "[当前]"} " else resolutions[index].label }


                    val replacements = mapOf(
                        "FHD" to "高清",
                        "SD" to "标清"
                    )

                    val replacedArray = items.map { str ->
                        replacements.entries.fold(str) { acc, (key, value) ->
                            acc.replace(key, value)
                        }
                    }.toTypedArray()

                    if (isShow) {
                        AlertDialog.Builder(this@DeviceLiveActivity)
                            .setTitle("选择视频码流")
                            .setItems(replacedArray) { _, which ->
                                run {
//                                    Tips.show("切换至 ${resolutions[which].label} ...")
                                    deviceLiveMediaSource.switchVideoResolution(resolutions[which].value)

                                    if ("SD" == resolutions[which].label) {
                                        binding.tvClarity.text = "标清"
                                    } else if ("FHD" == resolutions[which].label) {
                                        binding.tvClarity.text = "高清"
                                    }
                                }
                            }
                            .create()
                            .show()
                    }
                } else {
                    Tips.show("查询码流设置失败 ${it.message}")
                }
            }
        }
    }

    private fun launchLocalPlayback() {
        if (!hasSdCard) {
            Tips.show("设备没有插入SD卡")
            return
        }

        DevicePlaybackActivity.launch(this, deviceId)
    }

    private fun launchCloudPlayback() {
        if (lanMode) {
            Tips.show("本地直连模式下不可用")
            return
        }

        CloudPlaybackActivity.launch(this, deviceId)
    }

    override fun onResume() {
        super.onResume()
        TGLog.i(TAG, "[onResume] ")
        deviceLiveMediaSource.enableProduce(true)
        deviceMediaRender.play(true)

        checkJpg()
//        checkRecord()
    }

    private fun checkRecord() {

        val builder: OkHttpClient.Builder = OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .hostnameVerifier(AllowAllHostnameVerifier())

        val client: OkHttpClient = builder.build()
        val retrofit = Retrofit.Builder()
            .client(client)
            .baseUrl("http://192.168.179.1:8088")
            .addConverterFactory(GsonConverterFactory.create(Gson()))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
            .build()
        val productService: MainService = retrofit.create(MainService::class.java)

        val params = HashMap<String, Any>()
        params["cmd"] = "get_video_list"
        val dataMap = hashMapOf(
            "start_time" to 1755206456L,
            "end_time" to 1755231656L
        )
        params["data"] = dataMap

        productService.postRecode(params)
            .subscribeOn(AndroidSchedulers.mainThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object :
                CustomDisposableSubscriberNew<Any>(baseContext) {
                override fun onNext(bean: Any) {
                    LogUtil.e("bean：" + bean)
                }

                override fun onError(e: Throwable) {
                    super.onError(e)
                }
            })

    }


    override fun onPause() {
        super.onPause()
        TGLog.i(TAG, "[onPause] ")
        deviceLiveMediaSource.enableProduce(false)
        deviceMediaRender.play(false)

        if (deviceStorageMediaSource != null) {
            deviceStorageMediaSource!!.enableProduce(false)
            deviceMediaRender.play(false)
        }

        mediaCaptor?.stopCaptureVideo()
        mediaCaptor?.stopCaptureAudio()
        binding.videoChatPreviewContainer.gone()

        binding.talkBack.setImageDrawable(
            ContextCompat.getDrawable(
                this,
                R.drawable.ic_baseline_mic_off_24
            )
        )
        binding.videoChat.setImageDrawable(
            ContextCompat.getDrawable(
                this,
                R.drawable.ic_video_chat_off
            )
        )

        playbackQuery = null

        handler.removeCallbacks(updateRecode)
    }

    override fun onDestroy() {
        super.onDestroy()
        deviceLiveMediaSource.onBitrate = null
        deviceLiveMediaSource.onFrameRate = null
        deviceFacade.disconnect()
        deviceFacade.unObserveConnectStatus(connectStatusObserver)
    }

    private fun createCenterLayoutParams() = FrameLayout.LayoutParams(
        FrameLayout.LayoutParams.MATCH_PARENT,
        FrameLayout.LayoutParams.MATCH_PARENT
    ).apply { gravity = Gravity.CENTER }

    private fun talkback() {

        if (!deviceFacade.connected()) {
            Tips.show("等设备连接成功后，再使用对讲")
            return
        }

        if (!deviceMediaRender.playing) {
            Tips.show("当前未在播放！")
            return
        }

        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.RECORD_AUDIO
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                this.requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), 100)
            }
            Tips.show("需要录音权限")
            return
        }

        if (mediaCaptor?.audioCapturing == true) {
            mediaCaptor?.stopCaptureAudio()
            binding.talkBack.setImageDrawable(
                ContextCompat.getDrawable(
                    this,
                    R.drawable.ic_baseline_mic_off_24
                )
            )
        } else {
            mediaCaptor?.startCaptureAudio()
            binding.talkBack.setImageDrawable(
                ContextCompat.getDrawable(
                    this,
                    R.drawable.ic_baseline_mic_on_24
                )
            )
        }
    }

    private fun screenRecord() {

        if (!deviceMediaRender.playing) {
            Tips.show("当前未在播放！")
            return
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.READ_MEDIA_IMAGES
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                this.requestPermissions(
                    arrayOf(
                        Manifest.permission.READ_MEDIA_IMAGES,
                        Manifest.permission.READ_MEDIA_VIDEO
                    ), 100
                )
                Tips.show("需要存储权限")
                return
            }
        } else {
            if (ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    this.requestPermissions(
                        arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                        100
                    )
                }
                Tips.show("需要存储权限")
                return
            }
        }

//        deviceMediaRender.setRecordScale(2.0f)
        if (deviceMediaRender.screenRecord().isStarted()) {
            val file = File(albumPath, "TG-${System.currentTimeMillis()}.mp4")
            deviceMediaRender.screenRecord().finish(file.absolutePath) {
                if (it) Tips.show("录屏已保存到 ${file.absolutePath}")
            }
            binding.screenRecord.setImageDrawable(
                ContextCompat.getDrawable(
                    this,
                    R.drawable.ic_video_record_normal
                )
            )
        } else {
            deviceMediaRender.screenRecord().start()
            binding.screenRecord.setImageDrawable(
                ContextCompat.getDrawable(
                    this,
                    R.drawable.ic_video_record_on
                )
            )
            Tips.show("开始录屏，再次点击结束录屏")
        }

        Log.i(TAG, "[RecordStatusObserver][onClicked] ")
    }

    private var runnable = Runnable {
        binding.llVolume.gone()
    }

    private fun switchAudio() {
//        if (!deviceMediaRender.muted) {
//            muteAudio()
//        } else {
//            binding.audio.setImageDrawable(
//                ContextCompat.getDrawable(
//                    this,
//                    R.drawable.ic_baseline_volume_on_white
//                )
//            )
//            deviceMediaRender.mute(false)
//        }

        if (binding.llVolume.isVisible()) {
            binding.llVolume.gone()
        } else {
            binding.llVolume.visible()
            handler.removeCallbacks(runnable)
            handler.postDelayed(runnable, 5000)
        }
    }

    private fun muteAudio() {
        binding.audio.setImageDrawable(
            ContextCompat.getDrawable(
                this,
                R.drawable.ic_baseline_volume_off_24
            )
        )
        deviceMediaRender.mute(true)
    }

    private fun screenshot() {
        if (!deviceMediaRender.playing) {
            Tips.show("当前未在播放！")
            return
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.READ_MEDIA_IMAGES
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                this.requestPermissions(
                    arrayOf(
                        Manifest.permission.READ_MEDIA_IMAGES,
                        Manifest.permission.READ_MEDIA_VIDEO
                    ), 100
                )
                Tips.show("需要存储权限")
                return
            }
        } else {
            if (ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    this.requestPermissions(
                        arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                        100
                    )
                }
                Tips.show("需要存储权限")
                return
            }
        }

        deviceMediaRender.screenshot()?.let {

            val file = File(albumPath, "TG-${System.currentTimeMillis()}.jpg")

//            BitmapUtil.saveBitmapToFile(file, it, Bitmap.CompressFormat.JPEG)

            if (file.exists()) {
                val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
                val uri = Uri.fromFile(file)
                intent.data = uri
                sendBroadcast(intent)
                Tips.show("截图已保存到 ${file.absolutePath}")
            }
        }
    }

    private fun switchFullScreen() {
        if (isLandscape) {
            binding.bottomLayout.visibility = View.VISIBLE
            binding.topBar.visibility = View.VISIBLE
            binding.opButtons.visibility = View.VISIBLE
            binding.llBottom.visibility = View.VISIBLE
            binding.rvRecording.visibility = View.VISIBLE
            binding.shadow.visibility = View.VISIBLE
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
            isLandscape = false


            binding.playerContainer.post {
                deviceMediaRender.resize()
            }

            binding.playerContainer.layoutParams = FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                width / 16 * 9.toInt()
            )

            ImmersionBar.with(this).reset()
            ImmersionBar.with(this).statusBarColor(R.color.basic_color_secondary_2)
                .fitsSystemWindows(true).statusBarDarkFont(true).init()

            binding.container.setBackgroundColor(
                ContextCompat.getColor(
                    baseContext,
                    R.color.basic_color_secondary_2
                )
            )


            if (binding.tvHd.isActivated || binding.tvSd.isActivated) {
                binding.rvRecording.visible()
                binding.clDetail.gone()
            } else {
                binding.rvRecording.gone()
                binding.clDetail.visible()
            }

        } else {
            binding.bottomLayout.visibility = View.GONE
            binding.topBar.visibility = View.GONE
            binding.opButtons.visibility = View.GONE
            binding.shadow.visibility = View.GONE
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
            binding.llBottom.visibility = View.GONE
            binding.rvRecording.visibility = View.GONE
            isLandscape = true
//            binding.playerContainer.postDelayed({
//                Tips.show("使用物理返回键退出全屏")
//            }, 100)


            binding.playerContainer.post {
                deviceMediaRender.resize()
            }

            binding.playerContainer.layoutParams = FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                width
            )

            binding.container.setBackgroundColor(
                ContextCompat.getColor(
                    baseContext,
                    R.color.black
                )
            )

            ImmersionBar.with(this).reset()
            ImmersionBar.with(this).statusBarColor(R.color.black)
                .hideBar(BarHide.FLAG_HIDE_STATUS_BAR).statusBarDarkFont(false).init()
//            if (supportActionBar != null) {
//                supportActionBar!!.hide();
//            }
//
//            // 设置全屏
//            setFullScreen()
        }
    }

    private fun setFullScreen() {
        val decorView = window.decorView
        val flags = (View.SYSTEM_UI_FLAG_FULLSCREEN
                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)

        decorView.systemUiVisibility = flags

        // 适配刘海屏（Android 9+）
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            val params = window.attributes
            params.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
            window.attributes = params
        }


    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean =
        if (KeyEvent.KEYCODE_BACK == keyCode) {
            if (isLandscape) {
                switchFullScreen()
                true
            } else {
                finish()
                true
            }
        } else super.onKeyDown(keyCode, event)


    private fun connectToWifi(
        url: String,
        item: DeviceStoragePlayback.Index?,
        pbDownload: ProgressBar?,
        type: String,
        timestamp: Long?
    ) {
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> connectWithNetworkSpecifier(
                url,
                item,
                pbDownload,
                type,
                timestamp
            )

            else -> connectWithLegacyWifiManager()
        }
    }

    @RequiresApi(Build.VERSION_CODES.Q)
    private fun connectWithNetworkSpecifier(
        url: String,
        item: DeviceStoragePlayback.Index?,
        pbDownload: ProgressBar?,
        type: String,
        timestamp: Long?
    ) {
        val specifier = android.net.wifi.WifiNetworkSpecifier.Builder()
            .setSsid(SSID)
            .setWpa2Passphrase(PASSWORD)
            .build()

        val request = NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .setNetworkSpecifier(specifier)
            .build()

        val connectivityManager =
            getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

        val callback = object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                super.onAvailable(network)
                // 将应用绑定到此网络
                connectivityManager.bindProcessToNetwork(network)
                runOnUiThread {
                    ToastUtils.showShort("已连接至 $SSID")
                }
                if (type == TYPE_DOWNLOAD_VIDEO) {
                    downloadVideo(url.trim(), item!!, pbDownload!!)
                } else if (type == TYPE_DOWNLOAD_JPG) {
                    downloadJpg(url.trim(), timestamp!!)
                }
            }

            override fun onUnavailable() {
                super.onUnavailable()
                runOnUiThread {
                    ToastUtils.showShort("连接失败 $SSID")
                }
            }
        }

        connectivityManager.requestNetwork(request, callback)
    }

    private fun connectWithLegacyWifiManager() {
        val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager

        // 确保WiFi已开启
        if (!wifiManager.isWifiEnabled) {
            wifiManager.isWifiEnabled = true
        }

        // 配置WiFi网络
        val config = WifiConfiguration().apply {
            SSID = "\"$SSID\""  // 必须加双引号
            preSharedKey = "\"$PASSWORD\""
            allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK)
        }

        // 查找是否已有配置
        val existingNetworkId = findNetworkId(wifiManager, SSID)

        val networkId = if (existingNetworkId != -1) {
            existingNetworkId
        } else {
            wifiManager.addNetwork(config)
        }

        if (networkId != -1) {
            wifiManager.disconnect()
            wifiManager.enableNetwork(networkId, true)
            wifiManager.reconnect()
            ToastUtils.showShort("正在连接至 $SSID")
        } else {
            ToastUtils.showShort("创建网络配置失败")
        }
    }

    private fun findNetworkId(wifiManager: WifiManager, ssid: String): Int {
        val configuredNetworks = wifiManager.configuredNetworks ?: return -1

        for (config in configuredNetworks) {
            // 移除可能的双引号进行比较
            val configSsid = config.SSID.replace("\"", "")
            if (configSsid == ssid) {
                return config.networkId
            }
        }
        return -1
    }

    private fun disconnectWifi() {
        if (wifiManager.isWifiEnabled) {
            // 获取当前连接的网络
            val currentNetwork = getCurrentNetwork()

            if (currentNetwork != null) {
                // 断开当前连接
                wifiManager.disconnect()
                ToastUtils.showShort("已断开当前WiFi连接")
            } else {
                ToastUtils.showShort("当前未连接任何WiFi")
            }
        } else {
            ToastUtils.showShort("WiFi未启用")
        }
    }

    private fun getCurrentNetwork(): String? {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            val connectivityManager =
                getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val network = connectivityManager.activeNetwork
            val capabilities = connectivityManager.getNetworkCapabilities(network)

            if (capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true) {
                val wifiInfo = capabilities.transportInfo as android.net.wifi.WifiInfo
                return wifiInfo.ssid.replace("\"", "")
            }
        } else {
            val connectionInfo = wifiManager.connectionInfo
            if (connectionInfo != null && connectionInfo.networkId != -1) {
                return connectionInfo.ssid.replace("\"", "")
            }
        }
        return null
    }


}